package com.skynet.supervision.aop.uac;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.skynet.supervision.aop.uac.beans.UACTokenInfo;
import com.skynet.supervision.utils.UuidUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Date;

/**
 * @author xuchao
 * @date 2023-03-08 12:27
 */

@Component
public class JwtUtil {

    @Value("${skynet.uac.jwt.secret:UACTokenSecret###}")
    private String jwtSecret = "UACTokenSecret###";

    //过期时间设置为一周
    @Value("${skynet.uac.jwt.expireIn:604800}")
    private Integer expireInSec = 604800;

    private static final String USER_ID_KEY = "userId";
    private static final String SYS_NODE_CODE_KEY = "sysNodeCode";

    private final Integer REFRESH_TOKEN_EXPIRE_IN_SEC = 3600 * 24 * 7;

    private String createToken(String tid, String sysNodeCode, String userId, Instant issueAt, Instant expireAt) {
        Algorithm algorithm = Algorithm.HMAC256(jwtSecret);
        return JWT.create()
                .withJWTId(tid)
                .withClaim(SYS_NODE_CODE_KEY, sysNodeCode)
                .withClaim(USER_ID_KEY, userId)
                .withIssuedAt(Date.from(issueAt))
                .withExpiresAt(Date.from(expireAt))
                .sign(algorithm);
    }

    public UACTokenInfo generateToken(String sysNodeCode, String userId) {
        Instant now = Instant.now();
        Instant expireAt = now.plusSeconds(expireInSec);
        Instant refreshTokenExpireAt = now.plusSeconds(REFRESH_TOKEN_EXPIRE_IN_SEC);
        String tid = UuidUtils.randomUUID();
        String token = createToken(tid, sysNodeCode, userId, now, expireAt);
        String refreshToken = createToken(tid, sysNodeCode, userId, now, refreshTokenExpireAt);
        UACTokenInfo res = new UACTokenInfo();
        res.setId(tid);
        res.setExpireIn(expireInSec.longValue());
        res.setRefreshTokenExpireIn(REFRESH_TOKEN_EXPIRE_IN_SEC.longValue());
        res.setToken(token);
        res.setExpireAt(expireAt.getEpochSecond());
        res.setRefreshToken(refreshToken);
        res.setRefreshTokenExpireAt(refreshTokenExpireAt.getEpochSecond());
        return res;
    }

    public JwtPayloadInfo verify(String token) {
//        Instant now = Instant.now();
        try {
            Algorithm algorithm = Algorithm.HMAC256(jwtSecret);
            JWTVerifier verifier = JWT.require(algorithm)
//                    .acceptExpiresAt(now.getEpochSecond())
                    .withClaimPresence(USER_ID_KEY)
                    .withClaimPresence(SYS_NODE_CODE_KEY)
                    .withClaimPresence("exp")
                    .withClaimPresence("iat")
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            JwtPayloadInfo info = new JwtPayloadInfo();
            info.setId(jwt.getId());
            info.setSysNodeCode(jwt.getClaim(SYS_NODE_CODE_KEY).asString());
            info.setUserId(jwt.getClaim(USER_ID_KEY).asString());
            info.setIssueAt(jwt.getIssuedAt().getTime());
            info.setExpireAt(jwt.getExpiresAt().getTime());
//            info.setIssueAt(jwt.getIssuedAt().getTime() / 1000L);
//            info.setExpireAt(jwt.getExpiresAt().getTime() / 1000L);
            return info;
        } catch (Exception e) {
            return null;
        }
    }

    public Integer getInfoFromToken(String token, String filed) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim(filed).asInt();
    }

    @Data
    public static class JwtPayloadInfo {

        private String id;
        private String sysNodeCode;
        private String userId;
        private Long expireAt;
        private Long issueAt;
    }
}

